/*
 * This file is part of the quickTools support library, dubbed "LucasCode"
 *
 * Copyright (C) 2005-2008 Lucas Romero
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Xml;

namespace AutoUpdateControl
{
    public partial class AutoUpdateControl : UserControl
    {
        public AutoUpdateControl()
        {
            InitializeComponent();
            Visible = false;
            Dock = DockStyle.Bottom;
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void AutoUpdateControl_Load(object sender, EventArgs e)
        {
            lStatus.Text = lang.Init;
        }

        public delegate void UpdateProgressChangedEventHandler(object sender, UpdateEventArgs e);
        public delegate void UpdateCheckCompleteEventHandler(AutoUpdateControl sender, UpdateCheckEventArgs e);
        public event UpdateProgressChangedEventHandler UpdateProgressChanged;
        public event UpdateCheckCompleteEventHandler UpdateCheckComplete;
        private string m_UpdateFileURL = string.Empty;
        private string m_DownloadedFile = string.Empty;
        private string m_ErrorMessage = string.Empty;
        private string m_UpdateURL = string.Empty;
        Version m_InstalledVersion;
        UsageInfo m_UsageInfo;
        UpdateStatus m_UpdateStatus = UpdateStatus.Idle;
        public int HTTPTimeout = 10000;
	    public string DownloadedFile
	    {
	        get
	        {
                return m_DownloadedFile;
	        }
	    }
	    public string ErrorMessage
	    {
	        get
	        {
                return m_ErrorMessage;
	        }
	    }
	    public string UpdateFileURL
	    {
	        get
	        {
                return m_UpdateFileURL;
	        }
	    }
	    public void Cancel()
	    {
            m_UpdateStatus = UpdateStatus.Failed;
	    }
	    public bool hasUpdate(string UpdateURL,Version InstalledVersion,UsageInfo info)
	    {
            string extendedurl;
            if (info == null)
                extendedurl = UpdateURL;
            else
                extendedurl = UpdateURL + "?i=" + info.UniqueID + "&v=" + info.CurrentVersion;
            
            lStatus.Text = lang.UpdateCheck;
            XmlDocument doc = new XmlDocument();
            doc.Load(UpdateURL);

            XmlNode n = doc.SelectSingleNode("UpdateInformation/Mirrors");
            Random r = new Random();
            m_UpdateFileURL = n.ChildNodes[r.Next(n.ChildNodes.Count)].Attributes["Url"].Value;
            if (!m_UpdateFileURL.EndsWith("/"))
                m_UpdateFileURL += "/";


            n = doc.SelectSingleNode("UpdateInformation/Program");
            Version RecentVersion = new Version(n.Attributes["RecentVersion"].Value);
            m_UpdateFileURL += n.Attributes["UpdateFile"].Value;
            
	        if(RecentVersion > InstalledVersion)
	            return true;
	        else 
	            return false;
	    }
	    public void hasUpdateAsync(string UpdateURL,Version InstalledVersion,UsageInfo info)
	    {
            Visible = true;
            if (UpdateCheckComplete == null)
                throw new Exception("You must have the UpdateCheckComplete-event configured to check for an update asynchronously!");
            m_UpdateURL = UpdateURL;
            m_InstalledVersion = InstalledVersion;
	        m_UsageInfo = info;
            ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncCheck));
	    }
	    private void StartAsyncCheck(object dummy)
	    {
	        bool hasUpd = false;
	        bool failed = true;
	        try
	        {
                hasUpd = hasUpdate(m_UpdateURL, m_InstalledVersion, m_UsageInfo);
                if (hasUpd)
                {
                    lStatus.Text = lang.UpdateNewVersion;
                    lStatus.Cursor = Cursors.Hand;
                }
                else
                    lStatus.Text = lang.UpdateNewestVersion;
	            failed = false;
	        }
	        catch(Exception ex)
	        {
	            failed = true;
	        }
	        UpdateCheckEventArgs ev = new UpdateCheckEventArgs(hasUpd,failed);
            if (UpdateCheckComplete != null)
                UpdateCheckComplete(this, ev);
	    }
    }
    public class UsageInfo
    {
        public string UniqueID = string.Empty;
        public string CurrentVersion = "Unknown";
        public UsageInfo(string UniqueID, string CurrentVersion)
        {
            this.UniqueID = UniqueID;
            this.CurrentVersion = CurrentVersion;
        }
    }
    public class UpdateCheckEventArgs : EventArgs
    {
        public UpdateCheckEventArgs(bool hasUpdate, bool Failed)
        {
            m_hasUpdate = hasUpdate;
            m_Failed = Failed;

        }
        public bool hasUpdate
        {
            get
            {
                return m_hasUpdate;
            }
        }
        public bool Failed
        {
            get
            {
                return m_Failed;
            }
        }

        bool m_hasUpdate = false;
        bool m_Failed = false;
    }
    public class UpdateEventArgs : EventArgs
    {
        public UpdateEventArgs(UpdateStatus Status, int Progress, string ErrorMessage)
        {
            m_UpdateStatus = Status;
            m_Progress = Progress;
            m_ErrorMessage = ErrorMessage;
        }
        private int m_Progress = 0;
        private UpdateStatus m_UpdateStatus = UpdateStatus.Idle;
        private string m_ErrorMessage = string.Empty;
        #region Public get's
        public string ErrorMessage
        {
            get
            {
                return m_ErrorMessage;
            }
        }

        public UpdateStatus Status
        {
            get
            {
                return m_UpdateStatus;
            }
        }
        public int Progress
        {
            get
            {
                return m_Progress;
            }
        }
        #endregion
    }
    public enum UpdateStatus
    {
        Idle,
        Checking,
        Downloading,
        Installing,
        Complete,
        Failed
    }
}